#include "preHeader.h"
#include "BitMask.h"

#define U8_SIZE(n) ((n >> 3) + (n & ((1 << 3) - 1) ? 1 : 0))
#define U8_BIT_CLR(Array,i) BIT_CLR(Array[i >> 3], i & ((1 << 3) - 1))
#define U8_BIT_SET(Array,i) BIT_SET(Array[i >> 3], i & ((1 << 3) - 1))
#define U8_BIT_ISSET(Array,i) BIT_ISSET(Array[i >> 3], i & ((1 << 3) - 1))

CBitMask::CBitMask()
: m_BitMask(NULL)
, m_BitCount(0)
, m_BlockCount(0)
{
}

CBitMask::~CBitMask()
{
	if (m_BitMask != NULL) {
		delete[] m_BitMask;
	}
}

void CBitMask::Resize(size_t n)
{
	SAFE_DELETE_ARRAY(m_BitMask);
	m_BitCount = n;
	m_BlockCount = U8_SIZE(n);
	if (m_BlockCount != 0) {
		m_BitMask = new uint8[m_BlockCount]();
	}
}

void CBitMask::Read(INetPacket& pck)
{
	pck.Take(m_BitMask, m_BlockCount);
}

void CBitMask::Write(INetPacket& pck) const
{
	pck.Append(m_BitMask, m_BlockCount);
}

bool CBitMask::IsDirty(size_t i) const
{
	DBGASSERT(i < m_BitCount);
	return U8_BIT_ISSET(m_BitMask, i);
}

bool CBitMask::IsDirty() const
{
	for (size_t i = 0; i < m_BlockCount; ++i) {
		if (m_BitMask[i] != 0) {
			return true;
		}
	}
	return false;
}

void CBitMask::SetDirty(size_t i)
{
	DBGASSERT(i < m_BitCount);
	U8_BIT_SET(m_BitMask, i);
}

void CBitMask::ClearDirty(size_t i)
{
	DBGASSERT(i < m_BitCount);
	U8_BIT_CLR(m_BitMask, i);
}

void CBitMask::Reset()
{
	std::fill_n(m_BitMask, m_BlockCount, 0);
}

size_t CBitMask::FindFirst() const
{
	for (size_t i = 0; i < m_BitCount; ++i) {
		if (U8_BIT_ISSET(m_BitMask, i)) {
			return i;
		}
	}
	return npos;
}

size_t CBitMask::FindNext(size_t i) const
{
	for (++i; i < m_BitCount; ++i) {
		if (U8_BIT_ISSET(m_BitMask, i)) {
			return i;
		}
	}
	return npos;
}
